#include "thread_impl_win32.h"


namespace sys{
	DWORD __stdcall thread_proc(LPVOID);

	thread* create_thread(kcwstr _name, thread_route* _route, bool _auto_start, dword _stack_size)
	{
		win32_thread* thread = new win32_thread(_name);

		if (thread->create(_route, _auto_start, _stack_size))
			return thread;

		thread->release();
		return nullptr;
	}

	win32_thread::win32_thread(kcwstr _name)
	{
		m_name = _name;
	}

	bool win32_thread::create(thread_route* _route, bool _autostart, dword _stack_size)
	{
		m_stack_size	= _stack_size;
		m_proute		= _route;
		m_is_paused		= !_autostart;

		HANDLE handle = ::CreateThread(nullptr
			, (dword)_stack_size
			, thread_proc
			, this
			, _autostart ? 0 : CREATE_SUSPENDED
			, NULL);

		if (handle == 0)
		{
			return false;
		}

		if (_autostart)
		{
			Sleep(1);
		}

		m_hthread = handle;

		return true;
	}

	bool win32_thread::start()
	{
		if (is_valid() && is_paused())
		{
			if (-1 != ::ResumeThread(m_hthread))
			{
				m_is_paused = false;
			}
		}
		return false;
	}

	bool win32_thread::pause()
	{
		if ( running() )
		{

			if (-1 != ::SuspendThread(m_hthread))
			{
				m_is_paused = true;
			}
		}
		return false;
	}

	bool win32_thread::terminal(dword _exit_code)
	{
		if (!running())
		{
			return false;
		}

		::TerminateThread(m_hthread, _exit_code);

		::CloseHandle(m_hthread);
		m_hthread = 0;

		return true;

	}
	
	bool win32_thread::join(dword _mesc)
	{
		if (!running())
		{
			return false;
		}

		if (_mesc == 0)
			_mesc = INFINITE;

		int rst = ::WaitForSingleObject(m_hthread, _mesc);

		if (rst == WAIT_OBJECT_0 || rst == WAIT_ABANDONED)
		{
			CloseHandle(m_hthread);
			m_hthread = 0;
			return true;
		}
		return false;
	}

	win32_thread::~win32_thread()
	{
		if (running())
		{
			terminal(infinite);
		}
		cmn::safe_release(m_proute);
	}

	dword win32_thread::release()
	{
		delete this;
		return 0;
	}

	DWORD __stdcall thread_proc(LPVOID _param)
	{
		sys::win32_thread* pthread = (sys::win32_thread*)_param;

		TlsSetValue(sys::win32_thread::TLS_INDEX_THREAD, pthread->m_hthread);

		pthread->m_proute->main();

		return 0;
	}
}



